#include <iostream>
#include <string>

using std::cout;
using std::endl;

/* 
    饿汉式单例模式：
    - 饿汉：饿了肯定要饥不择食。所以在单例类定义的时候就进行实例化。static 成员变量在编译时就初始化，着急了老哥，饿了吧
    - 在访问量比较大，或者可能访问的线程比较多时，采用饿汉实现，可以实现更好的性能。
    - 这是以空间换时间。 
    - 线程安全
*/
class Print
{
private:
    // Print() { count = 0; }
    Print() : count(0) {}
    Print(const Print &) {}
    Print &operator=(const Print &) = delete;

public:
    static Print *getInstance()
    {
        return p;
    }

    void printWords(const char *s)
    {
        cout << s << endl;
        this->count++;
        cout << "count = " << count << endl;
    }

private:
    static Print *p;
    int count;
};
Print *Print::p = new Print;

class SingleMode {
public:
    static SingleMode& getInstance() {
        static SingleMode sing;
        return sing;
    }

private:
  SingleMode(){};
  SingleMode(SingleMode &sing) {cout << "copy constructed" <<endl;};
  SingleMode &operator=(const SingleMode &sing) = delete;

};


/* 
    懒汉式单例模式：
    - 懒汉：故名思义，不到万不得已就不会去实例化类，也就是说在第一次用到类实例的时候才会去实例化一个对象。
    - 在访问量较小，甚至可能不会去访问的情况下，采用懒汉实现，这是以时间换空间。
    - 急什么，用我的时候我再实例化，不用我，就没我事
    - 非线程安全
*/
class LazyPrint
{
private:
    LazyPrint() {}
    LazyPrint(const Print &) {}
    LazyPrint &operator=(const Print &) = delete;

public:
    static LazyPrint *getInstance()
    {
        if (m_p == nullptr)
        {
            m_p = new LazyPrint;
        }
        return m_p;
    }

    void printWords(const char *s)
    {
        cout << s << endl;
    }

private:
    static LazyPrint *m_p;
};

LazyPrint *LazyPrint::m_p = nullptr;

void hungryTest()
{
    Print *pIns = Print::getInstance();
    Print *pIns1 = pIns->getInstance();
    Print *pIns2 = Print::getInstance();

    if (pIns == pIns1)
    {
        cout << "pIns==pIns1" << endl;
    }
    else
    {
        cout << "pIns!=pIns1" << endl;
    }
    pIns->printWords("ABC");
    pIns->printWords("DEF");
    pIns->printWords("GHI");
}

void lazyTest()
{
    LazyPrint *pIns = LazyPrint::getInstance();
    LazyPrint *pIns1 = pIns->getInstance();
    LazyPrint *pIns2 = LazyPrint::getInstance();

    if (pIns == pIns1)
    {
        cout << "pIns==pIns1" << endl;
    }
    else
    {
        cout << "pIns!=pIns1" << endl;
    }
    pIns->printWords("ABC");
    pIns1->printWords("DEF");
    pIns2->printWords("GHI");

    delete pIns;
    // delete pIns1;

    cout << pIns << " " << pIns1 << " " << pIns2 << endl;
}

void test01() // test delete keyword  vs winGCC linuxGCC has different expression
{
    // int a = 20;
    int *p = new int(66);
    int *p1 = p;
    cout << p << " " << p1 << " " << endl;
    delete p;
    delete p1;

    cout << p << " " << p1 << " " << endl;
    cout << p << " " << p1 << " " << endl;
    cout << *p << " " << *p1 << " " << endl;
    cout << *p << " " << *p1 << " " << endl;

    int * pp = (int *)0x1100;
    cout << *pp << endl;

    cout << "-------------------" << endl;

}

void test02() {
    // SingleMode* sing0 = SingleMode::getInstance();
    // SingleMode* sing1 = SingleMode::getInstance();
    // SingleMode* sing2 = sing0->getInstance();
    // cout << sing0 << endl;
    // cout << sing1 << endl;
    // cout << sing2 << endl;
    SingleMode& sing0 = SingleMode::getInstance();
    SingleMode& sing1 = SingleMode::getInstance();
    SingleMode& sing2 = SingleMode::getInstance();
    cout << &sing0 << endl;
    cout << &sing1 << endl;
    cout << &sing2 << endl;
}

int main()
{
    // hungryTest();
    // lazyTest();
    // test01();
    test02();
    return 0;
}